import 'dart:async';
import 'dart:math';
import 'dart:typed_data';
import 'dart:ui' as ui;

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

class ColorFilterDemo extends StatefulWidget {
  ColorFilterDemo({Key? key}) : super(key: key);

  @override
  State<ColorFilterDemo> createState() => _ColorFilterDemoState();
}

class _ColorFilterDemoState extends State<ColorFilterDemo>
    with SingleTickerProviderStateMixin {
  late ui.Image fillImage;
  var rotationValue = 0.0;
  bool isImageLoaded = false;
  late Animation<double> animation;
  late AnimationController controller;

  void initState() {
    super.initState();
    init();
    controller =
        AnimationController(duration: const Duration(seconds: 2), vsync: this);
    animation = Tween<double>(begin: 0, end: 1.0).animate(CurvedAnimation(
      parent: controller,
      curve: Curves.linear,
    ))
      ..addListener(() {
        setState(() {});
      });
    controller.repeat();
  }

  Future<void> init() async {
    final ByteData data = await rootBundle.load('images/mb.jpeg');
    fillImage = await loadImage(Uint8List.view(data.buffer));
  }

  Future<ui.Image> loadImage(Uint8List img) async {
    final Completer<ui.Image> completer = Completer();
    ui.decodeImageFromList(img, (ui.Image img) {
      setState(() {
        isImageLoaded = true;
      });
      return completer.complete(img);
    });
    return completer.future;
  }

  @override
  Widget build(BuildContext context) {
    if (this.isImageLoaded) {
      return CustomPaint(
        painter: ColorFilterPainter(
          bgImage: fillImage,
          rotationValue: animation.value,
        ),
        child: Container(
          width: MediaQuery.of(context).size.width,
          height: MediaQuery.of(context).size.height,
        ),
      );
    } else {
      return CircularProgressIndicator();
    }
  }
}

class ColorFilterPainter extends CustomPainter {
  final ui.Image bgImage;
  final double rotationValue;

  ColorFilterPainter({
    required this.bgImage,
    required this.rotationValue,
  });
  @override
  void paint(Canvas canvas, Size size) {
    var paint = Paint();

    //paint.colorFilter = ColorFilter.mode(Colors.blue, BlendMode.color);
    //paint.colorFilter = ColorFilter.linearToSrgbGamma();
    const greyScale = ColorFilter.matrix(<double>[
      0.2126,
      0.7152,
      0.0722,
      0,
      0,
      0.2126,
      0.7152,
      0.0722,
      0,
      0,
      0.2126,
      0.7152,
      0.0722,
      0,
      0,
      0,
      0,
      0,
      1,
      0,
    ]);
    const sepia = ColorFilter.matrix(<double>[
      0.393,
      0.769,
      0.189,
      0,
      0,
      0.349,
      0.686,
      0.168,
      0,
      0,
      0.272,
      0.534,
      0.131,
      0,
      0,
      0,
      0,
      0,
      1,
      0,
    ]);
    const invert = ColorFilter.matrix(<double>[
      -1,
      0,
      0,
      0,
      255,
      0,
      -1,
      0,
      0,
      255,
      0,
      0,
      -1,
      0,
      255,
      0,
      0,
      0,
      1,
      0,
    ]);
    const diff = ColorFilter.matrix(<double>[
      0.5,
      0.5,
      0,
      0,
      0,
      0,
      0.5,
      0.5,
      0,
      0,
      0.5,
      0,
      0.5,
      0,
      0,
      0,
      0,
      0,
      1,
      0,
    ]);
    var colorRotation = ColorFilter.matrix(<double>[
      1 - rotationValue,
      0,
      rotationValue,
      0,
      0,
      rotationValue,
      1 - rotationValue,
      0,
      0,
      0,
      0,
      rotationValue,
      1 - rotationValue,
      0,
      0,
      0,
      0,
      0,
      1,
      0
    ]);
    paint.colorFilter = colorRotation;

    canvas.drawImageRect(
      bgImage,
      Rect.fromLTRB(0, 0, bgImage.width.toDouble(), bgImage.height.toDouble()),
      Offset.zero & size,
      paint,
    );
  }

  @override
  bool shouldRepaint(covariant CustomPainter oldDelegate) {
    return true;
  }
}
